// locutor
// (c) 2009, Normen Müller, normen.mueller@gmail.com  
// $Id: RegistrySpecSanitize.scala 74 2010-05-07 21:01:48Z normen.mueller $
package locutor.spec.registry

import org.specs._
import org.specs.specification._

import java.io.File
import scaup.Views._
import scala.xml.XML
import scaup.io.FileType._
import locutor.svn.reg._
import locutor.spec.Util._

object RegistrySpecSanitize extends Specification("Sanitation") {
  def throwWarnings = addToSusVerb("throw warnings due to") 
  "Sanitation" should throwWarnings {
    "working copy is not registered" in {
      ioRemove("wca")
      ioMkDir("wca")
      newRegistry().sanitize(WCA) must throwA[RegistryWarning]
    }
  }
  
  
  def noEffects = addToSusVerb("have no effects due to")
  "Sanitation" should noEffects {
    "absence of redundancies" in {
      resetAllWC()
      setupWC("wcb")

      val r = newRegistry()
      r.insert(WCB)
      r.serialize()
      
      val xml =
        (<registry version="0.1" xmlns="http://locutor.kwarc.info">
           <wc xml:id={WCB.path.toMD5} url={URLB} root={WCB.path}>
             <external xml:id={(WCB/"/a").path.toMD5} own={WCB.path} rev="-1" url={URLA} tgt="a"/>
           </wc>
         </registry>)
      
      XML.loadFile(REG) must ==/(xml)
      
      r.sanitize(WCB)
      r.serialize()
      
      XML.loadFile(REG) must ==/(xml)
    }
  }

  
  def transWC = addToSusVerb("transform a working copy by mapping redundants to")
  "Sanitation" should transWC {    
    "sibling paths (1st example)" in {
      setupWC("wca")
      svnSetExternal("wca", (-1, "https://svn.kwarc.info/repos/sandbox/wca/a", "b/a"))
      svnCommit("wca", "")
       
      var r = newRegistry()
      r.insert(WCA)
      
      r.sanitize(WCA)
      r.serialize()
      
      XML.loadFile(REG) must ==/(
        (<registry version="0.1" xmlns="http://locutor.kwarc.info">
           <wc xml:id={WCA.path.toMD5} url={URLA} root={WCA.path}>
             <external xml:id={(WCA/"b/a").path.toMD5} own={WCA.path} rev="-1" url={(URLA.toURI/"a").toString} tgt="b/a" xref={"#"+WCA.path.toMD5}/>
           </wc>
         </registry>))
      (WCA/"b/a").typ must_== SYMLINK
      (WCA/"b/a").lnktgt must_== Some((WCA/"a").path)
    }
    "sibling paths (2nd example)" in {
      setupWC("wch")
      svnUpdate("wch")

      val r = newRegistry()
      r.insert(WCH)
      r.serialize()

      XML.loadFile(REG) must ==/(
        (<registry version="0.1" xmlns="http://locutor.kwarc.info">
           <wc xml:id={WCH.path.toMD5} url={URLH} root={WCH.path}>
             <external xml:id={(WCH/"doc/macros/cm").path.toMD5} own={(WCH/"doc/macros").path} rev="-1" url={URLA} tgt="cm"/>
               <external xml:id={(WCH/"projects/dockon/doc/macros").path.toMD5} own={(WCH/"projects/dockon/doc").path} rev="-1" url={(URLH.toURI/"doc/macros").toString} tgt="macros">
               <external xml:id={(WCH/"projects/dockon/doc/macros/cm").path.toMD5} own={(WCH/"projects/dockon/doc/macros").path} rev="-1" url={URLA} tgt="cm"/>
             </external>
           </wc>
         </registry>))
      
      r.sanitize(WCH)
      r.serialize()
      
      XML.loadFile(REG) must ==/(
        (<registry version="0.1" xmlns="http://locutor.kwarc.info">
           <wc xml:id={WCH.path.toMD5} url={URLH} root={WCH.path}>
             <external xml:id={(WCH/"doc/macros/cm").path.toMD5} own={(WCH/"doc/macros").path} rev="-1" url={URLA} tgt="cm"/>
             <external xml:id={(WCH/"projects/dockon/doc/macros").path.toMD5} own={(WCH/"projects/dockon/doc").path} rev="-1" url={(URLH.toURI/"doc/macros").toString} tgt="macros" xref={"#"+WCH.path.toMD5}/>
             </wc>
           </registry>))
      (WCH/"projects/dockon/doc/macros").typ must_== SYMLINK
      (WCH/"projects/dockon/doc/macros").lnktgt must_== Some((WCH/"doc/macros").path)
    }
    "parent paths" in {
      // Note: Subversion would perform an infinite update.
      //       locutor, however, doesn't due to udpate scopes in SVNUpdateClient even
      //       externals have not been transformed.
      setupWC("wca")
      svnSetExternal("wca", (-1, "https://svn.kwarc.info/repos/sandbox/wca", "b/a"))
      svnCommit("wca", "")
      
      val r = newRegistry()
      r.insert(WCA)
      
      r.sanitize(WCA)
      r.serialize()
      
      XML.loadFile(REG) must ==/(
        (<registry version="0.1" xmlns="http://locutor.kwarc.info">
           <wc xml:id={WCA.path.toMD5} url={URLA} root={WCA.path}>
             <external xml:id={(WCA/"b/a").path.toMD5} own={WCA.path} rev="-1" url={URLA} tgt="b/a" xref={"#"+WCA.path.toMD5}/>
           </wc>
         </registry>))
      (WCA/"b/a").typ must_== SYMLINK
      (WCA/"b/a").lnktgt must_== Some(WCA.path)
    }
    "external paths" in {
      setupWC("wca")
      setupWC("wcb")
      svnSetExternal("wcb", (-1, "https://svn.kwarc.info/repos/sandbox/wca", "a"), (-1, "https://svn.kwarc.info/repos/sandbox/wca", "b/a"))
      svnCommit("wcb", "")
      svnUpdate("wcb")
      
      val r = newRegistry()
      r.insert(WCB)
      r.serialize()
      
      XML.loadFile(REG) must ==/(
        (<registry version="0.1" xmlns="http://locutor.kwarc.info">
           <wc xml:id={WCB.path.toMD5} url={URLB} root={WCB.path}>
             <external xml:id={(WCB/"a").path.toMD5} own={WCB.path} rev="-1" url={URLA} tgt="a"/>
             <external xml:id={(WCB/"b/a").path.toMD5} own={WCB.path} rev="-1" url={URLA} tgt="b/a"/>
           </wc>
         </registry>))
      
      r.sanitize(WCB)
      r.serialize()
      
      XML.loadFile(REG) must ==/(
        (<registry version="0.1" xmlns="http://locutor.kwarc.info">
           <wc xml:id={WCB.path.toMD5} url={URLB} root={WCB.path}>
             <external xml:id={(WCB/"a").path.toMD5} own={WCB.path} rev="-1" url={URLA} tgt="a"/>
             <external xml:id={(WCB/"b/a").path.toMD5} own={WCB.path} rev="-1" url={URLA} tgt="b/a" xref={"#"+(WCB/"a").path.toMD5}/>
           </wc>
         </registry>)) 
      (WCB/"b/a").typ must_== SYMLINK
      (WCB/"b/a").lnktgt must_== Some((WCB/"a").path)
    }
    "other working copy paths (1st example)" in {
      setupWC("wca")
      setupWC("wcb")
      
      val r = newRegistry()
      r.insert(WCA)
      r.insert(WCB)
      
      r.sanitize(WCB)
      r.serialize()
      
      XML.loadFile(REG) must ==/(         
        (<registry version="0.1" xmlns="http://locutor.kwarc.info">
           <wc xml:id={WCA.path.toMD5} url={URLA} root={WCA.path}/>
           <wc xml:id={WCB.path.toMD5} url={URLB} root={WCB.path}>
             <external xml:id={(WCB/"a").path.toMD5} own={WCB.path} rev="-1" url={URLA} tgt="a" xref={"#"+WCA.path.toMD5}/>
           </wc>
         </registry>))
      (WCB/"a").typ must_== SYMLINK
      (WCB/"a").lnktgt must_== Some(WCA.path)
    }
    "other working copy paths (2nd example)" in {
      setupWC("wca")
      setupWC("wcf")
      setupWC("wcg")
      svnUpdate("wcf")
      svnUpdate("wcg")

      val r = newRegistry()
      r.insert(WCF)
      r.insert(WCG)
      r.serialize()
      
      XML.loadFile(REG) must ==/(         
          (<registry version="0.1" xmlns="http://locutor.kwarc.info">
             <wc xml:id={WCF.path.toMD5} url={URLF} root={WCF.path}>
               <external xml:id={(WCF/"a").path.toMD5} own={WCF.path} rev="-1" url={(URLA.toURI/"a").toString} tgt="a"/>
               <external xml:id={(WCF/"b").path.toMD5} own={WCF.path} rev="-1" url={(URLA.toURI/"b").toString} tgt="b"/>
             </wc>
             <wc xml:id={WCG.path.toMD5} url={URLG} root={WCG.path}>
               <external xml:id={(WCG/"a").path.toMD5} own={WCG.path} rev="-1" url={URLF} tgt="a">
                 <external xml:id={(WCG/"a/a").path.toMD5} own={(WCG/"a").path} rev="-1" url={(URLA.toURI/"a").toString} tgt="a"/>
                 <external xml:id={(WCG/"a/b").path.toMD5} own={(WCG/"a").path} rev="-1" url={(URLA.toURI/"b").toString} tgt="b"/>
               </external>
             </wc>
           </registry>))
      
      r.sanitize(WCG)
      r.serialize()

      XML.loadFile(REG) must ==/(
        (<registry version="0.1" xmlns="http://locutor.kwarc.info">
           <wc xml:id={WCF.path.toMD5} url={URLF} root={WCF.path}>
             <external xml:id={(WCF/"a").path.toMD5} own={WCF.path} rev="-1" url={(URLA.toURI/"a").toString} tgt="a"/>
             <external xml:id={(WCF/"b").path.toMD5} own={WCF.path} rev="-1" url={(URLA.toURI/"b").toString} tgt="b"/>
           </wc>
           <wc xml:id={WCG.path.toMD5} url={URLG} root={WCG.path}>
             <external xml:id={(WCG/"a").path.toMD5} own={WCG.path} rev="-1" url={URLF} tgt="a" xref={"#"+WCF.path.toMD5}/>
           </wc>
         </registry>))
      (WCG/"a").typ must_== SYMLINK
      (WCG/"a").lnktgt must_== Some(WCF.path)
    }
    "other working copy paths (3rd example)" in {
      setupWC("wca")
      setupWC("wcf")
      setupWC("wcg")
      svnUpdate("wcf")
      svnUpdate("wcg")

      val r = newRegistry()
      r.insert(WCF)
      r.insert(WCG)
      r.sanitize(WCG)
      r.insert(WCA)
      r.sanitize(WCF)
      r.serialize()
      
      XML.loadFile(REG) must ==/(
        (<registry version="0.1" xmlns="http://locutor.kwarc.info">
           <wc xml:id={WCA.path.toMD5} url={URLA} root={WCA.path}/>
           <wc xml:id={WCF.path.toMD5} url={URLF} root={WCF.path}>
             <external xml:id={(WCF/"a").path.toMD5} own={WCF.path} rev="-1" url={(URLA.toURI/"a").toString} tgt="a" xref={"#"+WCA.path.toMD5}/>
             <external xml:id={(WCF/"b").path.toMD5} own={WCF.path} rev="-1" url={(URLA.toURI/"b").toString} tgt="b" xref={"#"+WCA.path.toMD5}/>
           </wc>
           <wc xml:id={WCG.path.toMD5} url={URLG} root={WCG.path}>
             <external xml:id={(WCG/"a").path.toMD5} own={WCG.path} rev="-1" url={URLF} tgt="a" xref={"#"+WCF.path.toMD5}/>
           </wc>
       </registry>))
      (WCG/"a").typ must_== SYMLINK
      (WCG/"a").lnktgt must_== Some(WCF.path)
      (WCF/"a").typ must_== SYMLINK
      (WCF/"a").lnktgt must_== Some((WCA/"a").path)
      (WCF/"b").typ must_== SYMLINK
      (WCF/"b").lnktgt must_== Some((WCA/"b").path)
    }
    "other working copy paths (4th example)" in {
      setupWC("wca")
      setupWC("wcf")
      setupWC("wcg")
      svnUpdate("wcf")
      svnUpdate("wcg")
      
      val r = newRegistry()
      r.insert(WCA)
      r.insert(WCF)
      r.insert(WCG)
      r.serialize()
      
      r.sanitize(WCG)
      r.sanitize(WCF)
      r.serialize()
      
      XML.loadFile(REG) must ==/(
        (<registry version="0.1" xmlns="http://locutor.kwarc.info">
           <wc xml:id={WCA.path.toMD5} url={URLA} root={WCA.path}/>
           <wc xml:id={WCF.path.toMD5} url={URLF} root={WCF.path}>
             <external xml:id={(WCF/"a").path.toMD5} own={WCF.path} rev="-1" url={(URLA.toURI/"a").toString} tgt="a" xref={"#"+WCA.path.toMD5}/>
             <external xml:id={(WCF/"b").path.toMD5} own={WCF.path} rev="-1" url={(URLA.toURI/"b").toString} tgt="b" xref={"#"+WCA.path.toMD5}/>
           </wc>
           <wc xml:id={WCG.path.toMD5} url={URLG} root={WCG.path}>
             <external xml:id={(WCG/"a").path.toMD5} own={WCG.path} rev="-1" url={URLF} tgt="a" xref={"#"+WCF.path.toMD5}/>
           </wc>
         </registry>))
      (WCG/"a").typ must_== SYMLINK
      (WCG/"a").lnktgt must_== Some(WCF.path)
      (WCF/"a").typ must_== SYMLINK
      (WCF/"a").lnktgt must_== Some((WCA/"a").path)
      (WCF/"b").typ must_== SYMLINK
      (WCF/"b").lnktgt must_== Some((WCA/"b").path)
    }
    "other working copy paths (5th example)" in {
      setupWC("wca")
      setupWC("wcf")
      setupWC("wcg")
      svnUpdate("wcf")
      svnUpdate("wcg")
      
      val r = newRegistry()
      r.insert(WCA)
      r.insert(WCF)
      r.insert(WCG)
      r.sanitize(WCF)           
      r.sanitize(WCG)        
      r.serialize()
      
      XML.loadFile(REG) must ==/(
        (<registry version="0.1" xmlns="http://locutor.kwarc.info">
           <wc xml:id={WCA.path.toMD5} url={URLA} root={WCA.path}/>
           <wc xml:id={WCF.path.toMD5} url={URLF} root={WCF.path}>
             <external xml:id={(WCF/"a").path.toMD5} own={WCF.path} rev="-1" url={(URLA.toURI/"a").toString} tgt="a" xref={"#"+WCA.path.toMD5}/>
             <external xml:id={(WCF/"b").path.toMD5} own={WCF.path} rev="-1" url={(URLA.toURI/"b").toString} tgt="b" xref={"#"+WCA.path.toMD5}/>
           </wc>
           <wc xml:id={WCG.path.toMD5} url={URLG} root={WCG.path}>
             <external xml:id={(WCG/"a").path.toMD5} own={WCG.path} rev="-1" url={URLF} tgt="a" xref={"#"+WCF.path.toMD5}/>
           </wc>
         </registry>))
      (WCG/"a").typ must_== SYMLINK
      (WCG/"a").lnktgt must_== Some(WCF.path)
      (WCF/"a").typ must_== SYMLINK
      (WCF/"a").lnktgt must_== Some((WCA/"a").path)
      (WCF/"b").typ must_== SYMLINK
      (WCF/"b").lnktgt must_== Some((WCA/"b").path)
    }
    "other working copy paths (6th example)" in {
      setupWC("wca")
      setupWC("wcf")
      setupWC("wcg")
      
      val r = newRegistry()
      r.insert(WCA)
      r.insert(WCF)
      r.sanitize(WCF)
      
      r.insert(WCG)
      r.sanitize(WCG)
      
      r.serialize()
      
      XML.loadFile(REG) must ==/(
        (<registry version="0.1" xmlns="http://locutor.kwarc.info">
           <wc xml:id={WCA.path.toMD5} url={URLA} root={WCA.path}/>
           <wc xml:id={WCF.path.toMD5} url={URLF} root={WCF.path}>
             <external xml:id={(WCF/"a").path.toMD5} own={WCF.path} rev="-1" url={(URLA.toURI/"a").toString} tgt="a" xref={"#"+WCA.path.toMD5}/>
             <external xml:id={(WCF/"b").path.toMD5} own={WCF.path} rev="-1" url={(URLA.toURI/"b").toString} tgt="b" xref={"#"+WCA.path.toMD5}/>
           </wc>
           <wc xml:id={WCG.path.toMD5} url={URLG} root={WCG.path}>
             <external xml:id={(WCG/"a").path.toMD5} own={WCG.path} rev="-1" url={URLF} tgt="a" xref={"#"+WCF.path.toMD5}/>
           </wc>
         </registry>))
      (WCG/"a").typ must_== SYMLINK
      (WCG/"a").lnktgt must_== Some(WCF.path)
      (WCF/"a").typ must_== SYMLINK
      (WCF/"a").lnktgt must_== Some((WCA/"a").path)
      (WCF/"b").typ must_== SYMLINK
      (WCF/"b").lnktgt must_== Some((WCA/"b").path)
    }
    "external paths of other working copies (1st example)" in {
      setupWC("wca")
      setupWC("wcb")
      setupWC("wce")
      svnUpdate("wcb")
      
      val r = newRegistry()
      r.insert(WCB)
      r.insert(WCE)
      
      r.sanitize(WCE)
      r.serialize()
      
      XML.loadFile(REG) must ==/(
          (<registry version="0.1" xmlns="http://locutor.kwarc.info">
             <wc xml:id={WCB.path.toMD5} url={URLB} root={WCB.path}>
               <external xml:id={(WCB/"a").path.toMD5} own={WCB.path} rev="-1" url={URLA} tgt="a"/>
             </wc>
             <wc xml:id={WCE.path.toMD5} url={URLE} root={WCE.path}>
               <external xml:id={(WCE/"a").path.toMD5} own={WCE.path} rev="-1" url={URLA} tgt="a" xref={"#"+(WCB/"a").path.toMD5}/>
             </wc>
           </registry>))
      (WCE/"a").typ must_== SYMLINK
      (WCE/"a").lnktgt must_== Some((WCB/"a").path)
    }
    "external paths of other working copies (2nd example)" in {
      setupWC("wca")
      setupWC("wcb")
      setupWC("wce")
      svnUpdate("wcb")
      
      val r = newRegistry()
      r.insert(WCB)
      r.insert(WCE)
      
      r.sanitize(WCE)
      r.serialize()
      
      XML.loadFile(REG) must ==/(         
        (<registry version="0.1" xmlns="http://locutor.kwarc.info">
           <wc xml:id={WCB.path.toMD5} url={URLB} root={WCB.path}>
             <external xml:id={(WCB/"a").path.toMD5} own={WCB.path} rev="-1" url={URLA} tgt="a"/>
           </wc>
           <wc xml:id={WCE.path.toMD5} url={URLE} root={WCE.path}>
             <external xml:id={(WCE/"a").path.toMD5} own={WCE.path} rev="-1" url={URLA} tgt="a" xref={"#"+(WCB/"a").path.toMD5}/>
           </wc>
         </registry>))
      (WCE/"a").typ must_== SYMLINK
      (WCE/"a").lnktgt must_== Some((WCB/"a").path)
      
      r.insert(WCA)
      
      /* Note: wce/a is /not/ turned due to we discarded WC prioritization in redundancy resolution */
      r.sanitize(WCE)
      r.serialize()
      
      XML.loadFile(REG) must ==/(         
        (<registry version="0.1" xmlns="http://locutor.kwarc.info">
           <wc xml:id={WCA.path.toMD5} url={URLA} root={WCA.path}/>
           <wc xml:id={WCB.path.toMD5} url={URLB} root={WCB.path}>
             <external xml:id={(WCB/"a").path.toMD5} own={WCB.path} rev="-1" url={URLA} tgt="a"/>
           </wc>
           <wc xml:id={WCE.path.toMD5} url={URLE} root={WCE.path}>
             <external xml:id={(WCE/"a").path.toMD5} own={WCE.path} rev="-1" url={URLA} tgt="a" xref={"#"+(WCB/"a").path.toMD5}/>
           </wc>
         </registry>))
      (WCE/"a").typ must_== SYMLINK
      (WCE/"a").lnktgt must_== Some((WCB/"a").path)

      r.sanitize(WCB)
      r.serialize()
    
      XML.loadFile(REG) must ==/(         
        (<registry version="0.1" xmlns="http://locutor.kwarc.info">
           <wc xml:id={WCA.path.toMD5} url={URLA} root={WCA.path}/>
           <wc xml:id={WCB.path.toMD5} url={URLB} root={WCB.path}>
             <external xml:id={(WCB/"a").path.toMD5} own={WCB.path} rev="-1" url={URLA} tgt="a" xref={"#"+WCA.path.toMD5}/>
           </wc>
           <wc xml:id={WCE.path.toMD5} url={URLE} root={WCE.path}>
             <external xml:id={(WCE/"a").path.toMD5} own={WCE.path} rev="-1" url={URLA} tgt="a" xref={"#"+WCA.path.toMD5}/>
           </wc>
         </registry>))
      (WCB/"a").typ must_== SYMLINK
      (WCE/"a").typ must_== SYMLINK
      (WCB/"a").lnktgt must_== Some(WCA.path)
      (WCE/"a").lnktgt must_== Some(WCA.path)
    }
  }
  
  
  def idempotent = addToSusVerb("be idempotent")
  "Sanitation" should idempotent {
    "on redundants mapped to working copies" in {
      setupWC("wca")
      setupWC("wcf")
      setupWC("wcg")
      svnUpdate("wcf")
      svnUpdate("wcg")

      val r = newRegistry()
      r.insert(WCF)
      r.insert(WCG)
 
      r.sanitize(WCG)
      r.serialize()

      XML.loadFile(REG) must ==/(
        (<registry version="0.1" xmlns="http://locutor.kwarc.info">
           <wc xml:id={WCF.path.toMD5} url={URLF} root={WCF.path}>
             <external xml:id={(WCF/"a").path.toMD5} own={WCF.path} rev="-1" url={(URLA.toURI/"a").toString} tgt="a"/>
             <external xml:id={(WCF/"b").path.toMD5} own={WCF.path} rev="-1" url={(URLA.toURI/"b").toString} tgt="b"/>
           </wc>
           <wc xml:id={WCG.path.toMD5} url={URLG} root={WCG.path}>
             <external xml:id={(WCG/"a").path.toMD5} own={WCG.path} rev="-1" url={URLF} tgt="a" xref={"#"+WCF.path.toMD5}/>
           </wc>
         </registry>))
      (WCG/"a").typ must_== SYMLINK
      (WCG/"a").lnktgt must_== Some(WCF.path)

      r.insert(WCA)
      
      r.sanitize(WCG)
      r.serialize()
      
      XML.loadFile(REG) must ==/(
        (<registry version="0.1" xmlns="http://locutor.kwarc.info">
           <wc xml:id={WCA.path.toMD5} url={URLA} root={WCA.path}/>
           <wc xml:id={WCF.path.toMD5} url={URLF} root={WCF.path}>
             <external xml:id={(WCF/"a").path.toMD5} own={WCF.path} rev="-1" url={(URLA.toURI/"a").toString} tgt="a"/>
             <external xml:id={(WCF/"b").path.toMD5} own={WCF.path} rev="-1" url={(URLA.toURI/"b").toString} tgt="b"/>
           </wc>
           <wc xml:id={WCG.path.toMD5} url={URLG} root={WCG.path}>
             <external xml:id={(WCG/"a").path.toMD5} own={WCG.path} rev="-1" url={URLF} tgt="a" xref={"#"+WCF.path.toMD5}/>
           </wc>
         </registry>))
      (WCG/"a").typ must_== SYMLINK
      (WCG/"a").lnktgt must_== Some(WCF.path)
    }
  }

 
  def symLink = addToSusVerb("turn dependents due to")
  "Sanitation" should symLink {    
    "resolution of transitive symlinks (1st example)" in {
      setupWC("wca")
      setupWC("wcb")
      setupWC("wce")      
      svnUpdate("wcb")
      
      val r = newRegistry()
      r.insert(WCB)
      r.insert(WCE)
      r.sanitize(WCE)
      r.insert(WCA)
      r.sanitize(WCB)
      r.serialize()
      
      XML.loadFile(REG) must ==/(         
        (<registry version="0.1" xmlns="http://locutor.kwarc.info">
           <wc xml:id={WCA.path.toMD5} url={URLA} root={WCA.path}/>
           <wc xml:id={WCB.path.toMD5} url={URLB} root={WCB.path}>
             <external xml:id={(WCB/"a").path.toMD5} own={WCB.path} rev="-1" url={URLA} tgt="a" xref={"#"+WCA.path.toMD5}/>
           </wc>
           <wc xml:id={WCE.path.toMD5} url={URLE} root={WCE.path}>
             <external xml:id={(WCE/"a").path.toMD5} own={WCE.path} rev="-1" url={URLA} tgt="a" xref={"#"+WCA.path.toMD5}/>
           </wc>
         </registry>))
      (WCB/"a").typ must_== SYMLINK
      (WCE/"a").typ must_== SYMLINK
      (WCB/"a").lnktgt must_== Some(WCA.path)
      (WCE/"a").lnktgt must_== Some(WCA.path)
    }
    "resolution of transitive symlinks (2nd example)" in {
      setupWC("wca")
      setupWC("wcb")
      setupWC("wcd")      
      svnUpdate("wcb")
      
      val r = newRegistry()
      r.insert(WCB)
      r.insert(WCD)
      r.sanitize(WCD)
      r.serialize()
      
      XML.loadFile(REG) must ==/(         
        (<registry version="0.1" xmlns="http://locutor.kwarc.info">
           <wc xml:id={WCB.path.toMD5} url={URLB} root={WCB.path}>
             <external xml:id={(WCB/"a").path.toMD5} own={WCB.path} rev="-1" url={URLA} tgt="a"/>
           </wc>
           <wc xml:id={WCD.path.toMD5} url={URLD} root={WCD.path}>
             <external xml:id={(WCD/"a").path.toMD5} own={WCD.path} rev="-1" url={(URLA.toURI/"a").toString} tgt="a" xref={"#"+(WCB/"a").path.toMD5}/>
           </wc>
         </registry>))
      
      r.insert(WCA)
      r.sanitize(WCB)
      r.serialize()
      
      XML.loadFile(REG) must ==/(         
        (<registry version="0.1" xmlns="http://locutor.kwarc.info">
           <wc xml:id={WCA.path.toMD5} url={URLA} root={WCA.path}/>
           <wc xml:id={WCB.path.toMD5} url={URLB} root={WCB.path}>
             <external xml:id={(WCB/"a").path.toMD5} own={WCB.path} rev="-1" url={URLA} tgt="a" xref={"#"+WCA.path.toMD5}/>
           </wc>
           <wc xml:id={WCD.path.toMD5} url={URLD} root={WCD.path}>
             <external xml:id={(WCD/"a").path.toMD5} own={WCD.path} rev="-1" url={(URLA.toURI/"a").toString} tgt="a" xref={"#"+WCA.path.toMD5}/>
           </wc>
         </registry>))
      (WCB/"a").typ must_== SYMLINK
      (WCD/"a").typ must_== SYMLINK
      (WCB/"a").lnktgt must_== Some(WCA.path)
      (WCD/"a").lnktgt must_== Some((WCA/"a").path)
    }
    "resolution of transitive symlinks (3rd example)" in {
      setupWC("wca")
      setupWC("wcb")
      setupWC("wce")
      setupWC("wcd")
      svnUpdate("wcb")
      
      val r = newRegistry()
      r.insert(WCB)
      r.insert(WCE)
      r.insert(WCD)
      r.sanitize(WCE)
      r.sanitize(WCD)
      r.serialize()
      
      XML.loadFile(REG) must ==/(         
        (<registry version="0.1" xmlns="http://locutor.kwarc.info">
           <wc xml:id={WCB.path.toMD5} url={URLB} root={WCB.path}>
             <external xml:id={(WCB/"a").path.toMD5} own={WCB.path} rev="-1" url={URLA} tgt="a"/>
           </wc>
           <wc xml:id={WCD.path.toMD5} url={URLD} root={WCD.path}>
             <external xml:id={(WCD/"a").path.toMD5} own={WCD.path} rev="-1" url={(URLA.toURI/"a").toString} tgt="a" xref={"#"+(WCB/"a").path.toMD5}/>
           </wc>
           <wc xml:id={WCE.path.toMD5} url={URLE} root={WCE.path}>
             <external xml:id={(WCE/"a").path.toMD5} own={WCE.path} rev="-1" url={URLA} tgt="a" xref={"#"+(WCB/"a").path.toMD5}/>
           </wc>
         </registry>))
      
      r.insert(WCA)
      r.sanitize(WCB)
      r.serialize()
      
      XML.loadFile(REG) must ==/(         
        (<registry version="0.1" xmlns="http://locutor.kwarc.info">
           <wc xml:id={WCA.path.toMD5} url={URLA} root={WCA.path}/>
           <wc xml:id={WCB.path.toMD5} url={URLB} root={WCB.path}>
             <external xml:id={(WCB/"a").path.toMD5} own={WCB.path} rev="-1" url={URLA} tgt="a" xref={"#"+WCA.path.toMD5}/>
           </wc>
           <wc xml:id={WCD.path.toMD5} url={URLD} root={WCD.path}>
             <external xml:id={(WCD/"a").path.toMD5} own={WCD.path} rev="-1" url={(URLA.toURI/"a").toString} tgt="a" xref={"#"+WCA.path.toMD5}/>
           </wc>
           <wc xml:id={WCE.path.toMD5} url={URLE} root={WCE.path}>
             <external xml:id={(WCE/"a").path.toMD5} own={WCE.path} rev="-1" url={URLA} tgt="a" xref={"#"+WCA.path.toMD5}/>
           </wc>
         </registry>))
      (WCB/"a").typ must_== SYMLINK
      (WCD/"a").typ must_== SYMLINK
      (WCE/"a").typ must_== SYMLINK
      (WCB/"a").lnktgt must_== Some(WCA.path)
      (WCD/"a").lnktgt must_== Some((WCA/"a").path)
      (WCE/"a").lnktgt must_== Some(WCA.path)
    }
  }
  
  
  def noTrans = addToSusVerb("not transform a working copy due to")
  "Sanitation" should noTrans { 
    "redundant is defined /but/ does not yet exists" in {
      setupWC("wcb")
      setupWC("wce")
      
      val r = newRegistry()
      r.insert(WCB)
      r.insert(WCE)
      
      r.sanitize(WCE)
      r.serialize()
      
      XML.loadFile(REG) must ==/(
        (<registry version="0.1" xmlns="http://locutor.kwarc.info">
           <wc xml:id={WCB.path.toMD5} url={URLB} root={WCB.path}>
             <external xml:id={(WCB/"a").path.toMD5} own={WCB.path} rev="-1" url={URLA} tgt="a"/>
           </wc>
           <wc xml:id={WCE.path.toMD5} url={URLE} root={WCE.path}>
             <external xml:id={(WCE/"a").path.toMD5} own={WCE.path} rev="-1" url={URLA} tgt="a"/>
           </wc>
         </registry>))
      (WCE/"a").typ must_== NONE
    }
  }
    
  
  def notAffect = addToSusVerb("not affect the registry due to")
  "Sanitation" should notAffect {
    "changed /but/ not yet committed externals" in {
      setupWC("wca")
      setupWC("wcb")
      
      val r = newRegistry()
      r.insert(WCA)
      r.insert(WCB)
      r.sanitize(WCB)
      r.serialize()
      
      val xml =
        (<registry version="0.1" xmlns="http://locutor.kwarc.info">
           <wc xml:id={WCA.path.toMD5} url={URLA} root={WCA.path}/>
           <wc xml:id={WCB.path.toMD5} url={URLB} root={WCB.path}>
             <external xml:id={(WCB/"a").path.toMD5} own={WCB.path} rev="-1" url={URLA} tgt="a" xref={"#"+WCA.path.toMD5}/>
           </wc>
         </registry>)
      
      XML.loadFile(REG) must ==/(xml)
      (WCB/"a").typ must_== SYMLINK
      (WCB/"a").lnktgt must_== Some(WCA.path)
      
      /* !!! In such a state a sanitize reverts the change on externals definitions
       *     due to the fact they are not yet committed but the former (committed) state is
       *     registered. */
      
      ioRemove("wcb/a")
      svnSetExternal("wcb", (-1, "https://svn.kwarc.info/repos/sandbox/wca/a", "a"))
      svnUpdate("wcb")

      r.sanitize(WCB)
      r.serialize()
      
      XML.loadFile(REG) must ==/(xml)         
      (WCB/"a").typ must_== SYMLINK
      (WCB/"a").lnktgt must_== Some(WCA.path)
    }
  }
  
  
  def resetTrans = addToSusVerb("reset invalid transexs due to")
  "Sanitizing" should resetTrans { 
    "absence of both source and other potential redundants" in {
      setupWC("wca")
      setupWC("wcb")
      
      val r = newRegistry()      
      r.insert(WCA)
      r.insert(WCB)
      r.sanitize(WCB)
      
      ioRemove("wca")
      
      r.sanitize(WCB)
      r.serialize()
      
      XML.loadFile(REG) must ==/(         
        (<registry version="0.1" xmlns="http://locutor.kwarc.info">
           <wc xml:id={WCA.path.toMD5} url={URLA} root={WCA.path}/>
           <wc xml:id={WCB.path.toMD5} url={URLB} root={WCB.path}>
             <external xml:id={(WCB/"a").path.toMD5} own={WCB.path} rev="-1" url={URLA} tgt="a"/>
           </wc>
         </registry>))
      (WCB/"a").typ must_== NONE
      (WCB/"a") mustNot exist
    }
    "source differs in revision" in {
      /* A locutor commit /does/ not only modify registry entries
       * but also performs I/O re-transformations.
       * 
       * Therefore this test case is invalid and tested in RegistryUpdateTest, rsp.
       */
      true
    }
    "source differs in URL" in {
      /* A locutor commit /does/ not only modify registry entries
       * but also performs I/O re-transformations.  
       * 
       * Therefore this test case is invalid and tested in RegistryUpdateTest, rsp.
       */
      true
    }
  }
  
  
  def turnTrans = addToSusVerb("turn invalid transexs due to")
  "Sanitizing" should turnTrans { 
    "absence of source /but/ existence of other redundants" in {
      setupWC("wca")
      setupWC("wcb")
      setupWC("wce")
      svnUpdate("wcb")
      
      var r = newRegistry()
      r.insert(WCB)
      r.insert(WCE)
      r.sanitize(WCE)
      r.serialize()
      
      XML.loadFile(REG) must ==/(
        (<registry version="0.1" xmlns="http://locutor.kwarc.info">
           <wc xml:id={WCB.path.toMD5} url={URLB} root={WCB.path}>
             <external xml:id={(WCB/"a").path.toMD5} own={WCB.path} rev="-1" url={URLA} tgt="a"/>
           </wc>
           <wc xml:id={WCE.path.toMD5} url={URLE} root={WCE.path}>
             <external xml:id={(WCE/"a").path.toMD5} own={WCE.path} rev="-1" url={URLA} tgt="a" xref={"#"+(WCB/"a").path.toMD5}/>
           </wc>
         </registry>))
      (WCE/"a").typ must_== SYMLINK
      (WCE/"a").lnktgt must_== Some((WCB/"a").path)
      
      r.insert(WCA)
      
      ioRemove("wcb")
      
      /* Note: This test case only succeeds due to transex validation in ``transform'' in case of 
       *       case e@TEX(o,r,u,t,x) => drefOf(vs, e) match { ... case Some(d) => [X] }
       *  Actually the registry currently is inconsistent to the file system.
       *  A subsequent ``delete(WCB)'' or ``regsync'' would remove ``WCB''
       *  out of the registry and adapt dependents of WCB and as such
       *  lead to the same result as this test case.
       */
      r.sanitize(WCE)
      r.serialize()
      
      XML.loadFile(REG) must ==/(
        (<registry version="0.1" xmlns="http://locutor.kwarc.info">
           <wc xml:id={WCA.path.toMD5} url={URLA} root={WCA.path}/>
           <wc xml:id={WCB.path.toMD5} url={URLB} root={WCB.path}>
             <external xml:id={(WCB/"a").path.toMD5} own={WCB.path} rev="-1" url={URLA} tgt="a"/>
           </wc>
           <wc xml:id={WCE.path.toMD5} url={URLE} root={WCE.path}>
             <external xml:id={(WCE/"a").path.toMD5} own={WCE.path} rev="-1" url={URLA} tgt="a" xref={"#"+WCA.path.toMD5}/>
           </wc>
         </registry>))
      (WCE/"a").typ must_== SYMLINK
      (WCE/"a").lnktgt must_== Some(WCA.path)
    }
  }
  
  
  def synchronize = addToSusVerb("synchronize a working copy due to")
  "Sanitizing" should synchronize { 
    "recently committed cascading externals (1st example)" in {
      setupWC("wca")
      setupWC("wcb")
      setupWC("wcc")
      svnUpdate("wcb")
      
      val r = newRegistry()
      r.insert(WCB)
      
      svnSetExternal("wca/a", (-1, "https://svn.kwarc.info/repos/sandbox/wcc/b", "b"))
      svnCommit("wca", "")
      
      svnUpdate("wcb")

      r.sanitize(WCB)
      r.serialize()
      
      XML.loadFile(REG) must ==/(
        (<registry version="0.1" xmlns="http://locutor.kwarc.info">
           <wc xml:id={WCB.path.toMD5} url={URLB} root={WCB.path}>
             <external xml:id={(WCB/"a").path.toMD5} own={WCB.path} rev="-1" url={URLA} tgt="a">
               <external xml:id={(WCB/"a/a/b").path.toMD5} own={(WCB/"a/a").path} rev="-1" url={(URLC.toURI/"b").toString} tgt="b"/>
             </external>
           </wc>
         </registry>))
    }
    "recently committed cascading externals (2nd example)" in {
      setupWC("wca")
      setupWC("wcb")
      svnUpdate("wcb")
      
      val r = newRegistry()
      r.insert(WCA)
      r.insert(WCB)
      
      svnSetExternal("wca/a", (-1, "https://svn.kwarc.info/repos/sandbox/wcc", "b"))
      /* =========================================================================================== */
      /* Here we fake; svnCommit will be locutorCommit */
      svnCommit("wca", "")      
      val exts = new java.util.LinkedList[String]()
      exts.add("https://svn.kwarc.info/repos/sandbox/wcc b")      
      r.update(WCA, (WCA/"a"), exts)
      r.serialize()
      /* =========================================================================================== */
      
      XML.loadFile(REG) must ==/(
        (<registry version="0.1" xmlns="http://locutor.kwarc.info">
           <wc xml:id={WCA.path.toMD5} url={URLA} root={WCA.path}>
             <external xml:id={(WCA/"a/b").path.toMD5} own={(WCA/"a").path} rev="-1" url={URLC} tgt="b"/>
           </wc>
           <wc xml:id={WCB.path.toMD5} url={URLB} root={WCB.path}>
             <external xml:id={(WCB/"a").path.toMD5} own={WCB.path} rev="-1" url={URLA} tgt="a"/>
           </wc>
         </registry>))
      
      r.sanitize(WCB)
      r.serialize()
      
      XML.loadFile(REG) must ==/(
        (<registry version="0.1" xmlns="http://locutor.kwarc.info">
           <wc xml:id={WCA.path.toMD5} url={URLA} root={WCA.path}>
             <external xml:id={(WCA/"a/b").path.toMD5} own={(WCA/"a").path} rev="-1" url={URLC} tgt="b"/>
           </wc>
           <wc xml:id={WCB.path.toMD5} url={URLB} root={WCB.path}>
             <external xml:id={(WCB/"a").path.toMD5} own={WCB.path} rev="-1" url={URLA} tgt="a" xref={"#"+WCA.path.toMD5}/>
           </wc>
         </registry>))
    }
    "recently committed cascading externals (3rd example)" in {
      setupWC("wca")
      setupWC("wcb")
      svnUpdate("wcb")
      
      val r = newRegistry()
      r.insert(WCA)
      r.insert(WCB)
      
      svnSetExternal("wca/a", (-1, "https://svn.kwarc.info/repos/sandbox/wcb", "b"))
      /* =========================================================================================== */
      /* Here we fake; svnCommit will be locutorCommit */
      svnCommit("wca", "")      
      val exts = new java.util.LinkedList[String]()
      exts.add("https://svn.kwarc.info/repos/sandbox/wcb b")      
      r.update(WCA, (WCA/"a"), exts)
      r.serialize()
      /* =========================================================================================== */
      
      XML.loadFile(REG) must ==/(
        (<registry version="0.1" xmlns="http://locutor.kwarc.info">
           <wc xml:id={WCA.path.toMD5} url={URLA} root={WCA.path}>
             <external xml:id={(WCA/"a/b").path.toMD5} own={(WCA/"a").path} rev="-1" url={URLB} tgt="b" xref={"#"+WCB.path.toMD5}/>
           </wc>
           <wc xml:id={WCB.path.toMD5} url={URLB} root={WCB.path}>
             <external xml:id={(WCB/"a").path.toMD5} own={WCB.path} rev="-1" url={URLA} tgt="a"/>
           </wc>
         </registry>))
      
      r.sanitize(WCB)
      r.serialize()
      
      XML.loadFile(REG) must ==/(
        (<registry version="0.1" xmlns="http://locutor.kwarc.info">
           <wc xml:id={WCA.path.toMD5} url={URLA} root={WCA.path}>
             <external xml:id={(WCA/"a/b").path.toMD5} own={(WCA/"a").path} rev="-1" url={URLB} tgt="b" xref={"#"+WCB.path.toMD5}/>
           </wc>
           <wc xml:id={WCB.path.toMD5} url={URLB} root={WCB.path}>
             <external xml:id={(WCB/"a").path.toMD5} own={WCB.path} rev="-1" url={URLA} tgt="a" xref={"#"+WCA.path.toMD5}/>
           </wc>
         </registry>))
    }
    "recently committed cascading externals (4th example)" in {
      setupWC("wca")
      setupWC("wcb")
      setupWC("wcc")
      
      val r = newRegistry()
      r.insert(WCC)
      r.serialize()
      
      XML.loadFile(REG) must ==/(
        (<registry version="0.1" xmlns="http://locutor.kwarc.info">
           <wc xml:id={WCC.path.toMD5} url={URLC} root={WCC.path}>
             <external xml:id={(WCC/"a").path.toMD5} own={WCC.path} rev="-1" url={URLB} tgt="a"/>
           </wc>
         </registry>))

      svnUpdate("wcc")
      
      r.sanitize(WCC)
      r.serialize()
      
      XML.loadFile(REG) must ==/(
        (<registry version="0.1" xmlns="http://locutor.kwarc.info">
           <wc xml:id={WCC.path.toMD5} url={URLC} root={WCC.path}>
             <external xml:id={(WCC/"a").path.toMD5} own={WCC.path} rev="-1" url={URLB} tgt="a">
               <external xml:id={(WCC/"a/a").path.toMD5} own={(WCC/"a").path} rev="-1" url={URLA} tgt="a"/>
             </external>
           </wc>
         </registry>))
    }
  }
}
